﻿using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Net;
using System.Windows.Browser;
using Newtonsoft.Json.Linq;

namespace SilverTwitterSearch
{
    /// <summary>
    /// Main class for searching Tweets.
    /// </summary>
    /// <remarks>
    /// This is the main class for the Twitter-search. It provides 
    /// the functionality to search for Tweets asynchronously.
    /// Use the method <see cref="SearchTweetsAsync(string)"/>
    /// to start searching. After the search operation has finished, the event <see cref="SearchTweetsCompleted"/>
    /// is raised, returning the results in it's arguments.
    /// </remarks>
    public class TwitterSearch
    {
        /// <summary>
        /// Base-URI for the Twitter-Search
        /// </summary>
        private const string TWITTER_SEARCH_URI = @"http://search.twitter.com/search.json?q={0}{1}";

        /// <summary>
        /// Raised when an asynchronous search has finished and provides the
        /// result.
        /// </summary>
        public event EventHandler<SearchTweetsCompletedEventArgs> SearchTweetsCompleted;

        /// <summary>
        /// Searches Twitter for the given query using the default search options.
        /// </summary>
        /// <remarks>
        /// The event <see cref="SearchTweetsCompleted"/> is raised after the 
        /// operation has finished.
        /// </remarks>
        /// <param name="query">Query to search</param>
        public void SearchTweetsAsync(string query)
        {
            this.SearchTweetsAsync(query, null);
        }

        /// <summary>
        /// Searches Twitter for the given query using the given search options.
        /// </summary>
        /// <remarks>
        /// The event <see cref="SearchTweetsCompleted"/> is raised after the 
        /// operation has finished.
        /// </remarks>
        /// <param name="query">Query to search</param>
        /// <param name="options">search Options to be used</param>
        public void SearchTweetsAsync(string query, TwitterSearchOptions? options)
        {
            if (String.IsNullOrWhiteSpace(query))
            {
                throw new ArgumentNullException("query", "You must specify a query!");
            }

            string uri = String.Format(
                TwitterSearch.TWITTER_SEARCH_URI,
                HttpUtility.UrlEncode(query),
                options != null ? options.ToString() : String.Empty);

            var client = new WebClient();
            client.DownloadStringCompleted += DownloadCompleted;
            client.DownloadStringAsync(new Uri(uri));
        }

        /// <summary>
        /// Is called when the HTTP-Call to Twitter has finished.
        /// </summary>
        /// <param name="sender">Calling instance</param>
        /// <param name="e">Event arguments with the searchresult</param>
        private void DownloadCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            var result = JObject.Parse(e.Result);
            var tweets = (JArray)result["results"];

            this.OnSearchTweetsCompleted(
                new ObservableCollection<Tweet>(tweets.Select(t => Tweet.ReadFromJson(t)).ToList()));
        }

        /// <summary>
        /// Raises the SearchTweetsCompleted-Event.
        /// </summary>
        /// <param name="result">Result of the search</param>
        protected void OnSearchTweetsCompleted(ObservableCollection<Tweet> result)
        {
            if (this.SearchTweetsCompleted != null)
            {
                this.SearchTweetsCompleted(this, new SearchTweetsCompletedEventArgs(result));
            }
        }
    }
}